package com.flute.framework.autoprompt;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.flute.tools.data.DataIterator;
import com.flute.tools.util.StringUtil;

public class AutoPrompt {
	private static AutoPrompt instance;
	private Map<String, WordResult> result;
	private WordCategory category;
	private Logger log = Logger.getLogger(this.getClass());

	private AutoPrompt() {
		this.result = new HashMap<String, WordResult>();
	}

	public synchronized static AutoPrompt getInstance() {
		if (instance == null) {
			instance = new AutoPrompt();
		}

		return instance;
	}

	public List<Token> getPromptValues(String string) {
		if (string == null) {
			string = "";
		}
		string = StringUtil.getStandardString(string);
		string = SpecialChars.getStatndardString(string);
		List<Token> tokens = new ArrayList<Token>();
		WordResult wr = result.get(string);
		if (wr != null) {
			return wr.getTokens(null);
		}

		return tokens;
	}

	public List<Token> getPromptValues(String string, String key) {
		if (string == null) {
			string = "";
		}
		List<Token> tokens = new ArrayList<Token>();
		if (category != null && category.containsKey(key)) {
			string = StringUtil.getStandardString(string);
			string = SpecialChars.getStatndardString(string);

			WordResult wr = result.get(string);
			if (wr != null) {
				return wr.getTokens(key);
			}
		}

		return tokens;
	}

	public void update(DataIterator<TokenData> datas,
			ITrainningTokenBuilder tokenBuilder,
			DataIterator<TokenData> iterator) {
		datas.reset();
		delete(datas, tokenBuilder, iterator);
		datas.reset();
		while (datas.hasNext()) {
			train(datas.next(), tokenBuilder);
		}
		datas.close();
	}

	/**
	 * 重载update使其适应单个TokenData
	 * 
	 * @param datas
	 * @param tokenBuilder
	 * @param map
	 */
	public void update(TokenData datas, ITrainningTokenBuilder tokenBuilder,
			Map<String, Set<String>> map) {
		delete(datas, tokenBuilder, map);
		train(datas, tokenBuilder);
	}

	/**
	 * 重载update使其适应单个TokenData
	 * 
	 * @param data
	 * @param tokenBuilder
	 * @param map
	 */
	public void delete(TokenData data,
			ITrainningTokenBuilder tokenBuilder, Map<String, Set<String>> map) {
		Set<String> tokens = new HashSet<String>();
		Set<String> dataSet = new HashSet<String>();
		try {
			dataSet.add(data.getText());
			List<TrainningToken> tokenList = tokenBuilder.build(data);
			for (TrainningToken token : tokenList) {
				WordResult wr = (WordResult) this.result.get(token.getText());
				if (wr != null)
					if (wr.containsText(token.getToken().getOriginalText(),
							data.getKey())) {
						wr.deleteToken(token.getToken().getOriginalText(), data
								.getKey());
						tokens.add(token.getText() + data.getKey());
					}
			}
			map.put(data.getText(), tokens);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage());
		}
	}

	public void delete(DataIterator<TokenData> datas,
			ITrainningTokenBuilder tokenBuilder,
			DataIterator<TokenData> iterator) {

		Set<String> tokens = new HashSet<String>();
		Set<String> dataSet = new HashSet<String>();
		while (datas.hasNext()) {
			try {
				TokenData data = datas.next();
				dataSet.add(data.getText());
				List<TrainningToken> tokenList = tokenBuilder.build(data);
				for (TrainningToken token : tokenList) {
					WordResult wr = result.get(token.getText());
					if (wr != null) {
						if (wr.containsText(token.getToken().getOriginalText(),
								data.getKey())) {
							wr.deleteToken(token.getToken().getOriginalText(),
									data.getKey());
							tokens.add(token.getText() + data.getKey());
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		try{
			if (tokens.size() > 0) {
				while (iterator.hasNext()) {
					TokenData td = iterator.next();
					if (!dataSet.contains(td.getText())) {
						train(td, tokenBuilder, tokens);
					}
				}
			}	
		} finally {
			iterator.close();	
		}
	}

	public void againSortOut(DataIterator<TokenData> iterator,
			Map<String, Set<String>> map, ITrainningTokenBuilder tokenBuilder) {
		while (iterator.hasNext()) {
			TokenData td = (TokenData) iterator.next();
			if (!(map.containsKey(td.getText()))) {
				Set<String> hs = (HashSet<String>) map.get(td.getText());
				if ((hs != null) && (hs.size() > 0))
					train(td, tokenBuilder, (HashSet<String>) map.get(td
							.getText()));
			}
		}
	}

	private void train(TokenData data, ITrainningTokenBuilder tokenBuilder,
			Set<String> keySet) {
		try {
			if (tokenBuilder != null && data != null) {
				if (category.containsKey(data.getKey())) {
					for (TrainningToken token : tokenBuilder.build(data)) {
						if (keySet.contains(token.getText() + data.getKey())) {
							String text = token.getText();

							if (!result.containsKey(text)) {
								result.put(text, new WordResult(category));
							}

							result.get(text).addToken(token.getToken(),
									data.getKey());
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public synchronized void train(TokenData data,
			ITrainningTokenBuilder tokenBuilder) {
		try {
			if (tokenBuilder != null && data != null) {
				if (category.containsKey(data.getKey())) {
					for (TrainningToken token : tokenBuilder.build(data)) {
						String text = token.getText();

						if (!result.containsKey(text)) {
							result.put(text, new WordResult(category));
						}

						result.get(text).addToken(token.getToken(),
								data.getKey());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public synchronized void train(TrainningToken token) {
		String text = token.getText();

		if (!result.containsKey(text)) {
			result.put(text, new WordResult(category));
		}

		result.get(text).addToken(token.getToken(), null);
	}

	public synchronized WordCategory getCategory() {
		return category;
	}

	public synchronized void setCategory(WordCategory category) {
		this.category = category;
	}
}
